'''
dionysus - a web based dialogue management framework
Copyright (C) 2011  Eugeniu Costetchi <eugeniu.costetchi (at) tudor.lu>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

Created on Dec 31, 2010
'''
#===============================================================================
# QafException
#===============================================================================
from string import Template
from DialogueManager import utils
from DialogueManager.Context import Context
from DialogueManager.Parser import InputTypes, input_compatible
from DialogueManager.utils.utils import get_place_holders,\
    iterable_to_cvs_place_holder_values

class QafException(Exception):
    def __init__(self, value):
        self.value = value
    
    def __str__(self):
        return repr(self.value)

#===============================================================================
# QafTemplate
#===============================================================================
class QafTemplate(object):
    '''
    classdocs
    '''
    # place_holders = {'subject':'', 'object':'', 'aux_word1':'', 'aux_word2':'', 'aux_word3':''}
    def __init__(self, about, answer_type, questio_nlt, fact_nlt, fact_flt):
        '''
        Constructor
        '''
        self.about = about
        self.answer_type = answer_type
        self.questio_nlt = questio_nlt
        self.fact_nlt = fact_nlt
        self.fact_flt = fact_flt
        
    #===========================================================================
    # instantiate
    #===========================================================================
    def instantiate(self, place_holders={'subject':'', 'object':'', 'aux_word1':'', 'aux_word2':'', 'aux_word3':''}):
        return QafInstance(self, place_holders)

    def __str__(self):
        try:
            return 'QafTemplate:'+self.about+" ("+self.questio_nlt[0:12]+"...) "
        except:
            return 'QafTemplate:'+self.about
        
    def __repr__(self):
        return self.__str__()
    
#===============================================================================
# QafInstance
#===============================================================================
class QafInstance(object):
    
    ANSWER_ITEM_PLACE_HOLDER = 'answer_item'
    ANSWER_LIST_PLACE_HOLDER = Context.ANALYSED_TOKENS
    ANSWER_TYPE_PLACE_HOLDER = Context.ANALYSED_TYPE
    
    def __init__(self, template, place_holders={'subject':'', 'object':'', 'aux_word1':'', 'aux_word2':'', 'aux_word3':''}):
        self.__template = template
        self.__place_holders = place_holders
        
        self.__answer_instance = {Context.ANALYSED_TYPE:'', Context.ANALYSED_TOKENS:[]}
        self.__question_instance = self.__substitute_place_holders(self.__template.questio_nlt)
        self.__fact_instance = ''
        self.__formal_code = ''

    #===========================================================================
    # __set_placeholders  
    #===========================================================================
    @DeprecationWarning
    def __set_placeholders_individually(self, subject='', object='', aux_word1='', aux_word2='', aux_word3=''):
#        if len(subject) > 0 and len(object) > 0:
#            raise QafException('cannot have both object and subject defined, one must be asked about')
        self.place_holders['subject'] = subject
        self.place_holders['object'] = object
        self.place_holders['aux_word1'] = aux_word1
        self.place_holders['aux_word2'] = aux_word2
        self.place_holders['aux_word3'] = aux_word3
    
    #===========================================================================
    # __set_placeholders  
    #===========================================================================
    def __set_placeholders(self, placeholders):
        self.place_holders.update(placeholders)
        
#    #===========================================================================
#    # __check_place_holders
#    #===========================================================================
#    @DeprecationWarning
#    def __check_place_holders(self):
#        if len(self.__place_holders['subject']) > 0 and len(self.__place_holders['object']) > 0:
#            raise QafException('cannot have both *object* and *subject* provided in instance, one must be asked about')
#        if len(self.__place_holders['subject']) == 0 and len(self.__place_holders['object']) == 0:
#            raise QafException('cannot have both *object* and *subject* missing in instance, one must be asked about')
 
    #===========================================================================
    # __substitute_place_holders
    #===========================================================================
    def __substitute_place_holders(self, template, iterable_to_cvs=True):
        t = Template(template)
        kw = get_place_holders(t.template, only_identifiers=True)
        d = {}
        if iterable_to_cvs:
            d = iterable_to_cvs_place_holder_values(kw, self.__place_holders)
        else:
            for i in kw: d[i] = self.__place_holders[i]
        # replacing spaces by underscore, to comply with Turtle syntax
        for i in d:
            d[i] = d[i].replace(' ','_') 
        #
        sub = t.substitute(d)
        return sub

    #===========================================================================
    # question
    #===========================================================================
    def question(self):
        return self.__question_instance
    
    #===========================================================================
    # fact
    #===========================================================================
    def fact(self):
        return self.__fact_instance
    
    #===========================================================================
    # formal_code
    #===========================================================================
    def formal_code(self):
        return self.__formal_code

    #===========================================================================
    # about
    #===========================================================================
    def about(self):
        return self.__template.about
    
    def answer_type(self):
        return self.__template.answer_type
    
    def inject_answer(self, type, low):
        assert type
        assert low
        
        if not input_compatible( self.__template.answer_type, type): 
            raise QafException('Could not inject the answer because expected type is '+
                               self.__template.answer_type+' and instead received '+type)
            
        self.__answer_instance[Context.ANALYSED_TYPE] = type
        self.__answer_instance[Context.ANALYSED_TOKENS] = low
        self.__place_holders.update(self.__answer_instance)
        
        self.__fact_instance = self.__substitute_place_holders(self.__template.fact_nlt)
        
        for ai in self.__answer_instance[Context.ANALYSED_TOKENS]:
            self.__place_holders[QafInstance.ANSWER_ITEM_PLACE_HOLDER] = ai
            self.__formal_code += self.__substitute_place_holders(self.__template.fact_flt) + '\n'
    
    def __str__(self):
        try:
            return 'QafInstance:'+self.about()+" ("+self.question()[0:12]+"...) "
        except:
            return 'QafInstance:'+self.about()
    
    def __repr__(self):
        return self.__str__()
    
#t = Template("Do you know any kinds of ${word}")
#m = re.findall(r'\$\{[ \w ]+\}', "Do you know ${ sdf    } any kinds of ${word}")
#print m, utils.trim(m, distinguish_words=False)
#print t.substitute({'word':'dog', 'a':'a', 'b':'b'})
#print '----'
#i='${word}'
#d ={}
#d[i]=i[2:-1]
#print d
